package dao;

import interfaceDAO.IDAOStation;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;

import domain.HibernateUtil;
import domain.JCDecauxObject;
import domain.JCDecauxQuery;
import domain.Station;

public class DAOStation implements IDAOStation {
	private Map<Integer, JCDecauxObject> mappingIdToRTObject;

	/**
	 * Add RT values retrieve from JC Decaux web service to given station.
	 * 
	 * @param station
	 *            The station to enhance.
	 * @return Updated station with RT valus (nb available bikes, status
	 *         open/close, ...)
	 */
	private Station enhanceStationWithRTValuesStation(Station station) {
		try {
			if (mappingIdToRTObject == null) {
				mappingIdToRTObject = new JCDecauxQuery().sendRequest();
			}
			JCDecauxObject jcDecauxObj = mappingIdToRTObject.get(station
				.getNumber());

			if (jcDecauxObj != null) {
				station.updateDynamicData(jcDecauxObj);
			} else {
				System.err.println("Web service didn't "
						+ "retrieve object with number '" + station.getNumber()
						+ "'");
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return station;
	}

	/**
	 * Add RT information retrieved from JC Decaux web service to a list of
	 * stations retrieved from database.
	 * 
	 * @param dbStationList
	 *            The list of stations retrieved from DB.
	 * @return A new list containing stations with RT information (nb bikes, nb
	 *         available bikes, status open/close, ...).
	 */
	@SuppressWarnings("unchecked")
	private List<Station> enhanceStationList(List<?> dbStationList) {
		if (dbStationList != null) {
			List<Station> stationWithRTList = new ArrayList<Station>(
				dbStationList.size());
			for (Station dbStation : (List<Station>) dbStationList) {
				stationWithRTList
					.add(enhanceStationWithRTValuesStation(dbStation));
			}
			return stationWithRTList;
		} else {
			return Collections.EMPTY_LIST;
		}
	}

	/**
	 * Retrieve a list of station from given name.
	 * 
	 * @param name
	 *            The name of the station.
	 * @return A list of station which name is equal to name.
	 */
	public List<Station> getStationByName(String name) {

		Session session = HibernateUtil.getSessionFactory().openSession();
		session.beginTransaction();
		try {
			Criteria selectCriteria = session.createCriteria(Station.class);
			selectCriteria.add(Restrictions.eq("name", name));
			List<?> dbStations = selectCriteria.list();
			return enhanceStationList(dbStations);
		} finally {
			session.close();
		}
	}

	public Station getStationByNumber(int number) {
		Session session = HibernateUtil.getSessionFactory().openSession();
		session.beginTransaction();
		try {
			Criteria selectCriteria = session.createCriteria(Station.class);
			selectCriteria.add(Restrictions.eq("number", number));
			List<?> dbStations = selectCriteria.list();
			List<Station> stations = enhanceStationList(dbStations);
			if (stations != null && !stations.isEmpty()) {
				return stations.get(0);
			} else {
				return null;
			}
		} finally {
			session.close();
		}
	}

	/*
	 * public Station getStation(String lat, String lng) {
	 * 
	 * Station station = new Station(); Session session =
	 * HibernateUtil.getSessionFactory().openSession();
	 * session.beginTransaction(); Criteria selectCriteria =
	 * session.createCriteria(Station.class);
	 * 
	 * selectCriteria.add(Restrictions.like("latitude", lat)).add(
	 * Restrictions.like("longitude", lng)); List<?> res =
	 * selectCriteria.list();
	 * 
	 * if (res != null) { for (Object obj : res) { station =
	 * enhanceStationWithRTValuesStation((Station) obj); } } session.close();
	 * return station;
	 * 
	 * }
	 */

	public List<Station> getAllStations() {

		Session session = HibernateUtil.getSessionFactory().openSession();
		session.beginTransaction();
		try {
			Criteria selectCriteria = session.createCriteria(Station.class);
			List<?> dbStationList = selectCriteria.list();
			return enhanceStationList(dbStationList);

		} finally {
			session.close();
		}

	}

	/**
	 * Get all stations between an interval.
	 * <p/>
	 * Algo : Retrieve all station S with latitude Slat and longitude Slng so
	 * that
	 * <tt> Abs(Slat - lat) &gt;=latInt and Abs(Slng - lng) &gt;=lngInt</tt>.
	 * 
	 * @param lat
	 *            Center latitude.
	 * @param lng
	 *            Center longitude.
	 * @param latInt
	 *            Delta latitude.
	 * @param lngInt
	 *            Delta longitude.
	 */
	public List<Station> getAllStationsBetween(double lat, double lng,
			double latInt, double lngInt) {

		Session session = HibernateUtil.getSessionFactory().openSession();
		session.beginTransaction();
		try {

			double latMin = (lat - latInt);
			double latMax = (lat + latInt);
			double lngMin = (lng - lngInt);
			double lngMax = (lng + lngInt);

			Criteria selectCriteria = session.createCriteria(Station.class)
				.add(Restrictions.between("latitude", latMin, latMax))
				.add(Restrictions.between("longitude", lngMin, lngMax));

			List<?> dbStationList = selectCriteria.list();
			return enhanceStationList(dbStationList);
		} finally {
			// Add close instruction in finally block to be sure to call it!
			session.close();
		}

	}

	// /**
	// * Get all stations between an interval.
	// * <p/>
	// * Algo : Retrieve all station S with latitude Slat and longitude Slng so
	// * that
	// * <tt> Abs(Slat - lat) &gt;=latInt and Abs(Slng - lng) &gt;=lngInt</tt>.
	// *
	// * @param lat
	// * Center latitude.
	// * @param lng
	// * Center longitude.
	// * @param latInt
	// * Delta latitude.
	// * @param lngInt
	// * Delta longitude.
	// */
	// public ArrayList<Station> getAllStationsBetween(double lat, double lng,
	// double latInt, double lngInt) {
	//
	// BigDecimal bgLatMin = BigDecimal.valueOf(lat - latInt);
	// BigDecimal bgLatMax = BigDecimal.valueOf(lat + latInt);
	//
	// BigDecimal bgLngMin = BigDecimal.valueOf(lng - lngInt);
	// BigDecimal bgLngMax = BigDecimal.valueOf(lng + lngInt);
	//
	// ArrayList<Station> stations = new ArrayList<Station>();
	//
	// Session session = HibernateUtil.getSessionFactory().openSession();
	// session.beginTransaction();
	//
	// Criteria selectCriteria = session.createCriteria(Station.class);
	//
	// // selectCriteria.add(Restrictions.eq("name", name));
	// List<?> res = selectCriteria.list();
	//
	// if (res != null) {
	// for (Object obj : res) {
	// Station stat = (Station) obj;
	// try {
	// BigDecimal latStat = new BigDecimal(stat.getLatitude());
	// BigDecimal lngStat = new BigDecimal(stat.getLongitude());
	//
	// // verifier que les coordonees sont dans l'intevalle définie
	// if (latStat.compareTo(bgLatMin) >= 0
	// && latStat.compareTo(bgLatMax) <= 0
	// && lngStat.compareTo(bgLngMin) >= 0
	// && lngStat.compareTo(bgLngMax) <= 0) {
	// enhanceStationWithRTValuesStation(stat);
	// stations.add(stat);
	// }
	// } catch (Throwable t) {
	// t.printStackTrace();
	// }
	// }
	// }
	// session.close();
	// return stations;
	// }
}